Added another loader from Arjan to handle .ico files. Cool.
authorJonathan Blandford <jrb@redhat.com>
Mon, 29 Nov 1999 16:49:39 +0000 (16:49 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Mon, 29 Nov 1999 16:49:39 +0000 (16:49 +0000)
1999-11-29  Jonathan Blandford  <jrb@redhat.com>

        * src/Makefile.am (ICO_LIB): Added another loader from Arjan to
handle .ico files.  Cool.

gdk-pixbuf/ChangeLog
gdk-pixbuf/Makefile.am
gdk-pixbuf/gdk-pixbuf-io.c
gdk-pixbuf/io-ico.c [new file with mode: 0644]

index 940dcdc13b2241aff9b7e4362656445aa64a9bfa..c461d45b998c00d9838b1c9c0859d18c1a99c37e 100644 (file)
@@ -1,3 +1,8 @@
+1999-11-29  Jonathan Blandford  <jrb@redhat.com>
+
+       * src/Makefile.am (ICO_LIB): Added another loader from Arjan to
+       handle .ico files.  Cool.
+
 1999-11-24  Jonathan Blandford  <jrb@redhat.com>
 
        * src/io-bmp.c (OneLine24): new patch from Arjan to handle
index 9e1a12ff60453527cd8ff2d09e8a6c3f88cf40c3..afb095e5f14e8663cc68cd696ed912107b2ac6dd 100644 (file)
@@ -13,6 +13,8 @@ endif
 
 GIF_LIB = libpixbuf-gif.la
 
+ICO_LIB = libpixbuf-ico.la
+
 RAS_LIB = libpixbuf-ras.la
 
 if HAVE_TIFF
@@ -29,6 +31,7 @@ libexec_LTLIBRARIES =         \
        $(PNG_LIB)      \
        $(JPEG_LIB)     \
        $(GIF_LIB)      \
+       $(ICO_LIB)      \
        $(RAS_LIB)      \
        $(XPM_LIB)      \
        $(TIFF_LIB)     \
@@ -104,6 +107,13 @@ libpixbuf_gif_la_SOURCES = io-gif.c
 libpixbuf_gif_la_LDFLAGS = -avoid-version -module
 libpixbuf_gif_la_LIBADD =
 
+#
+# The ICO loader
+#
+libpixbuf_ico_la_SOURCES = io-ico.c
+libpixbuf_ico_la_LDFLAGS = -avoid-version -module
+libpixbuf_ico_la_LIBADD =
+
 #
 # The RAS loader
 #
index 698d15ed7a00d1770f2698e42cf48a52ea75e935..6f09ec2fde2c23bc8efa050adfc58d4f51b0bb1b 100644 (file)
@@ -136,6 +136,23 @@ pixbuf_check_sunras (guchar *buffer, int size)
        return TRUE;
 }
 
+static gboolean
+pixbuf_check_ico (guchar *buffer, int size)
+{
+       /* Note that this may cause false positives, but .ico's don't
+          have a magic number.*/
+       if (size < 6)
+               return FALSE;
+       if (buffer [0] != 0x0 ||
+           buffer [1] != 0x0 ||
+           buffer [2] != 0x1 ||
+           buffer [3] != 0x0 ||
+           buffer [5] != 0x0 )
+               return FALSE;
+
+       return TRUE;
+}
+
 
 static gboolean
 pixbuf_check_bmp (guchar *buffer, int size)
@@ -159,6 +176,7 @@ GdkPixbufModule file_formats [] = {
        { "xpm",  pixbuf_check_xpm, NULL,  NULL, NULL, NULL, NULL, NULL },
        { "pnm",  pixbuf_check_pnm, NULL,  NULL, NULL, NULL, NULL, NULL },
        { "ras",  pixbuf_check_sunras, NULL,  NULL, NULL, NULL, NULL, NULL },
+       { "ico",  pixbuf_check_ico, NULL,  NULL, NULL, NULL, NULL, NULL },
        { "bmp",  pixbuf_check_bmp, NULL,  NULL, NULL, NULL, NULL, NULL },
        { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
diff --git a/gdk-pixbuf/io-ico.c b/gdk-pixbuf/io-ico.c
new file mode 100644 (file)
index 0000000..c9e35a0
--- /dev/null
@@ -0,0 +1,698 @@
+/* GdkPixbuf library - Windows Bitmap image loader
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *
+ * Based on io-bmp.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+
+Icons are just like BMP's, except for the header.
+Known bugs:
+       * bi-tonal files aren't tested 
+
+*/
+
+#include <config.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include "gdk-pixbuf/gdk-pixbuf.h"
+#include "gdk-pixbuf/gdk-pixbuf-io.h"
+\f
+
+
+struct headerpair {
+       guint width;
+       guint height;
+       guint depth;
+       guint Negative;         /* Negative = 1 -> top down BMP,  
+                                  Negative = 0 -> bottom up BMP */
+};
+
+/* 
+
+These structures are actually dummies. These are according to
+the "Windows API reference guide volume II" as written by Borland,
+but GCC fiddles with the alignment of the internal members.
+
+*/
+
+struct BitmapFileHeader {
+       gushort bfType;
+       guint bfSize;
+       guint reserverd;
+       guint bfOffbits;
+};
+
+struct BitmapInfoHeader {
+       guint biSize;
+       guint biWidth;
+       guint biHeight;
+       gushort biPlanes;
+       gushort biBitCount;
+       guint biCompression;
+       guint biSizeImage;
+       guint biXPelsPerMeter;
+       guint biYPelsPerMeter;
+       guint biClrUsed;
+       guint biClrImportant;
+};
+
+static void DumpBIH(unsigned char *BIH)
+{                              /* For debugging */
+       printf("biSize      = %i \n",
+              (BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
+       printf("biWidth     = %i \n",
+              (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
+       printf("biHeight    = %i \n",
+              (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
+              (BIH[8]));
+       printf("biPlanes    = %i \n", (BIH[13] << 8) + (BIH[12]));
+       printf("biBitCount  = %i \n", (BIH[15] << 8) + (BIH[14]));
+       printf("biCompress  = %i \n",
+              (BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
+              (BIH[16]));
+       printf("biSizeImage = %i \n",
+              (BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
+              (BIH[20]));
+       printf("biXPels     = %i \n",
+              (BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
+              (BIH[24]));
+       printf("biYPels     = %i \n",
+              (BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
+              (BIH[28]));
+       printf("biClrUsed   = %i \n",
+              (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
+              (BIH[32]));
+       printf("biClrImprtnt= %i \n",
+              (BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
+              (BIH[36]));
+}
+
+/* 
+       This does a byte-order swap. Does glib have something like
+       be32_to_cpu() ??
+*/
+
+static unsigned int le32_to_cpu(guint i)
+{
+       unsigned int i2;
+       return i2;
+}
+
+/* 
+       Destroy notification function for the libart pixbuf 
+*/
+
+static void free_buffer(gpointer user_data, gpointer data)
+{
+       free(data);
+}
+
+
+/* Progressive loading */
+
+struct ico_progressive_state {
+       ModulePreparedNotifyFunc prepared_func;
+       ModuleUpdatedNotifyFunc updated_func;
+       gpointer user_data;
+
+       gint HeaderSize;        /* The size of the header-part (incl colormap) */
+       guchar *HeaderBuf;      /* The buffer for the header (incl colormap) */
+       gint BytesInHeaderBuf;  /* The size of the allocated HeaderBuf */
+       gint HeaderDone;        /* The nr of bytes actually in HeaderBuf */
+
+       gint LineWidth;         /* The width of a line in bytes */
+       guchar *LineBuf;        /* Buffer for 1 line */
+       gint LineDone;          /* # of bytes in LineBuf */
+       gint Lines;             /* # of finished lines */
+
+       gint Type;              /*  
+                                  24 = RGB
+                                  8 = 8 bit colormapped
+                                  1  = 1 bit bitonal 
+                                */
+
+
+       struct headerpair Header;       /* Decoded (BE->CPU) header */
+       
+       gint                    DIBoffset;
+       gint                    ImageScore;
+
+
+       GdkPixbuf *pixbuf;      /* Our "target" */
+};
+
+gpointer
+image_begin_load(ModulePreparedNotifyFunc prepared_func,
+                ModuleUpdatedNotifyFunc updated_func, gpointer user_data);
+void image_stop_load(gpointer data);
+gboolean image_load_increment(gpointer data, guchar * buf, guint size);
+
+
+
+/* Shared library entry point */
+GdkPixbuf *image_load(FILE * f)
+{
+       guchar *membuf;
+       size_t length;
+       struct ico_progressive_state *State;
+       int fd;
+
+       GdkPixbuf *pb;
+
+       State = image_begin_load(NULL, NULL, NULL);
+       membuf = g_malloc(4096);
+
+       g_assert(membuf != NULL);
+
+
+       while (feof(f) == 0) {
+               length = fread(membuf, 1, 4096, f);
+               if (length > 0)
+                       image_load_increment(State, membuf, length);
+
+       }
+       g_free(membuf);
+       if (State->pixbuf != NULL)
+               gdk_pixbuf_ref(State->pixbuf);
+
+       pb = State->pixbuf;
+
+       image_stop_load(State);
+       return State->pixbuf;
+}
+
+static void DecodeHeader(guchar *Data, gint Bytes,
+                        struct ico_progressive_state *State)
+{
+/* For ICO's we have to be very clever. There are multiple images possible
+   in an .ICO. For now, we select (in order of priority):
+     1) The one with the highest number of colors
+     2) The largest one
+ */   
+       gint IconCount = 0; /* The number of icon-versions in the file */
+       guchar *BIH; /* The DIB for the used icon */
+       guchar *Ptr;
+       gint I;
+       /* Step 1: The ICO header */
+       IconCount = (Data[5] << 8) + (Data[4]);
+       printf("There are %i icons in this file \n",IconCount);
+       State->HeaderSize = 6 + IconCount*16;
+       
+       if (State->HeaderSize>State->BytesInHeaderBuf) {
+               State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
+               State->BytesInHeaderBuf = State->HeaderSize;
+       }
+       if (Bytes < State->HeaderSize)
+               return;
+       
+       /* We now have all the "short-specs" of the versions 
+          So we iterate through them and select the best one */
+          
+       State->ImageScore = 0;
+       State->DIBoffset  = 0;
+       Ptr = Data + 6;
+       for (I=0;I<IconCount;I++) {
+               int ThisWidth, ThisHeight,ThisColors;
+               int ThisScore;
+               
+               ThisWidth = Ptr[0];
+               ThisHeight = Ptr[1];
+               ThisColors = (Ptr[2]);
+               if (ThisColors==0) 
+                       ThisColors=256; /* Yes, this is in the spec */
+               
+               printf("Option: %ix%ix%i ",ThisWidth,ThisHeight,ThisColors);
+       
+               ThisScore = ThisColors*1024+ThisWidth*ThisHeight; 
+
+               if (ThisScore>State->ImageScore) {
+                       State->ImageScore = ThisScore;
+                       State->DIBoffset = (Ptr[15]<<24)+(Ptr[14]<<16)+
+                                          (Ptr[13]<<8) + (Ptr[12]);
+                       printf("*");
+                                                                
+               }
+               
+               printf("\n");
+               
+               Ptr += 16;      
+       } 
+               
+       /* We now have a winner, pointed to in State->DIBoffset,
+          so we know how many bytes are in the "header" part. */
+             
+       State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
+       
+       if (State->HeaderSize>State->BytesInHeaderBuf) {
+               State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
+               State->BytesInHeaderBuf = State->HeaderSize;
+       }
+       if (Bytes<State->HeaderSize) 
+               return;   
+       
+       BIH = Data+State->DIBoffset;
+
+/*     DumpBIH(BIH);*/
+       
+       /* Add the palette to the headersize */
+               
+       State->Header.width =
+           (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
+       State->Header.height =
+           (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8])/2;
+           /* /2 because the BIH height includes the transparency mask */
+       State->Header.depth = (BIH[15] << 8) + (BIH[14]);;
+
+       State->Type = State->Header.depth;      /* This may be less trivial someday */
+       if (State->Lines>State->Header.height)
+               State->Type = 1;
+       
+       I =(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
+       if ((I==0)&&(State->Type==1))
+               I = 2*4;
+       if ((I==0)&&(State->Type==4))
+               I = 16*4;
+       if ((I==0)&&(State->Type==8))
+               I = 256*4;
+       
+       State->HeaderSize+=I;
+       
+       if (State->HeaderSize>State->BytesInHeaderBuf) {
+               State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
+               State->BytesInHeaderBuf = State->HeaderSize;
+       }
+       if (Bytes < State->HeaderSize)
+               return;
+
+       if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
+           || (BIH[19] != 0)) {
+               g_assert(0); /* Compressed icons aren't allowed */
+       }
+
+       if (State->Header.height < 0) {
+               State->Header.height = -State->Header.height;
+               State->Header.Negative = 1;
+       }
+       if (State->Header.width < 0) {
+               State->Header.width = -State->Header.width;
+               State->Header.Negative = 0;
+       }
+
+       if (State->Type == 24)
+               State->LineWidth = State->Header.width * 3;
+       if (State->Type == 8)
+               State->LineWidth = State->Header.width * 1;
+       if (State->Type == 4) {
+               State->LineWidth = State->Header.width/2;
+               if ((State->Header.width & 1) != 0)
+                       State->LineWidth++;
+       }
+       if (State->Type == 1) {
+               State->LineWidth = State->Header.width / 8;
+               if ((State->Header.width & 7) != 0)
+                       State->LineWidth++;
+       }
+
+       /* Pad to a 32 bit boundary */
+       if (((State->LineWidth % 4) > 0))
+               State->LineWidth = (State->LineWidth / 3) * 3 + 3;
+
+
+       if (State->LineBuf == NULL)
+               State->LineBuf = g_malloc(State->LineWidth);
+
+       g_assert(State->LineBuf != NULL);
+
+
+       if (State->pixbuf == NULL) {
+               State->pixbuf =
+                   gdk_pixbuf_new(ART_PIX_RGB, TRUE, 8,
+                                  (gint) State->Header.width,
+                                  (gint) State->Header.height);
+
+               if (State->prepared_func != NULL)
+                       /* Notify the client that we are ready to go */
+                       (*State->prepared_func) (State->pixbuf,
+                                                State->user_data);
+
+       }
+
+}
+
+/* 
+ * func - called when we have pixmap created (but no image data)
+ * user_data - passed as arg 1 to func
+ * return context (opaque to user)
+ */
+
+gpointer
+image_begin_load(ModulePreparedNotifyFunc prepared_func,
+                ModuleUpdatedNotifyFunc updated_func, gpointer user_data)
+{
+       struct ico_progressive_state *context;
+
+       context = g_new0(struct ico_progressive_state, 1);
+       context->prepared_func = prepared_func;
+       context->updated_func = updated_func;
+       context->user_data = user_data;
+
+       context->HeaderSize = 54;
+       context->HeaderBuf = g_malloc(14 + 40 + 4*256 + 512);
+       /* 4*256 for the colormap */
+       context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
+       context->HeaderDone = 0;
+
+       context->LineWidth = 0;
+       context->LineBuf = NULL;
+       context->LineDone = 0;
+       context->Lines = 0;
+
+       context->Type = 0;
+
+       memset(&context->Header, 0, sizeof(struct headerpair));
+
+
+       context->pixbuf = NULL;
+
+
+       return (gpointer) context;
+}
+
+/*
+ * context - returned from image_begin_load
+ *
+ * free context, unref gdk_pixbuf
+ */
+void image_stop_load(gpointer data)
+{
+       struct ico_progressive_state *context =
+           (struct ico_progressive_state *) data;
+
+
+       g_return_if_fail(context != NULL);
+
+       if (context->LineBuf != NULL)
+               g_free(context->LineBuf);
+       context->LineBuf = NULL;
+       if (context->HeaderBuf != NULL)
+               g_free(context->HeaderBuf);
+
+       if (context->pixbuf)
+               gdk_pixbuf_unref(context->pixbuf);
+
+       g_free(context);
+}
+
+
+static void OneLine24(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   (context->Header.height - context->Lines - 1);
+       else
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   context->Lines;
+       while (X < context->Header.width) {
+               Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2];
+               Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1];
+               Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0];
+               X++;
+       }
+
+}
+
+static void OneLine8(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   (context->Header.height - context->Lines - 1);
+       else
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   context->Lines;
+       while (X < context->Header.width) {
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 4 + 0] =
+                   context->HeaderBuf[4 * context->LineBuf[X] + 42+context->DIBoffset];
+               Pixels[X * 4 + 1] =
+                   context->HeaderBuf[4 * context->LineBuf[X] + 41+context->DIBoffset];
+               Pixels[X * 4 + 2] =
+                   context->HeaderBuf[4 * context->LineBuf[X] + 40+context->DIBoffset];
+               X++;
+       }
+}
+static void OneLine4(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   (context->Header.height - context->Lines - 1);
+       else
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   context->Lines;
+       
+       while (X < context->Header.width) {
+               guchar Pix;
+               
+               Pix = context->LineBuf[X/2];
+
+               Pixels[X * 4 + 0] =
+                   context->HeaderBuf[4 * (Pix>>4) + 42+context->DIBoffset];
+               Pixels[X * 4 + 1] =
+                   context->HeaderBuf[4 * (Pix>>4) + 41+context->DIBoffset];
+               Pixels[X * 4 + 2] =
+                   context->HeaderBuf[4 * (Pix>>4) + 40+context->DIBoffset];
+               X++;
+               if (X<context->Header.width) { 
+                       /* Handle the other 4 bit pixel only when there is one */
+                       Pixels[X * 4 + 0] =
+                           context->HeaderBuf[4 * (Pix&15) + 42+context->DIBoffset];
+                       Pixels[X * 4 + 1] =
+                           context->HeaderBuf[4 * (Pix&15) + 41+context->DIBoffset];
+                       Pixels[X * 4 + 2] =
+                           context->HeaderBuf[4 * (Pix&15) + 40+context->DIBoffset];
+                       X++;
+               }
+       }
+       
+}
+
+static void OneLine1(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   (context->Header.height - context->Lines - 1);
+       else
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   context->Lines;
+       while (X < context->Header.width) {
+               int Bit;
+
+               Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
+               Bit = Bit & 1;
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 4 + 0] = context->HeaderBuf[Bit + 32];
+               Pixels[X * 4 + 1] = context->HeaderBuf[Bit + 2 + 32];
+               Pixels[X * 4 + 2] = context->HeaderBuf[Bit + 4 + 32];
+               X++;
+       }
+}
+
+static void OneLineTransp(struct ico_progressive_state *context)
+{
+       gint X;
+       guchar *Pixels;
+
+       X = 0;
+       if (context->Header.Negative == 0)
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   (2*context->Header.height - context->Lines - 1);
+       else
+               Pixels = context->pixbuf->art_pixbuf->pixels +
+                   gdk_pixbuf_get_rowstride(context->pixbuf) *
+                   (context->Lines-context->Header.height);
+       while (X < context->Header.width) {
+               int Bit;
+
+               Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
+               Bit = Bit & 1;
+               /* The joys of having a BGR byteorder */
+               Pixels[X * 4 + 3] = 255-Bit*255;
+#if 0
+               if (Bit){
+                 Pixels[X*4+0] = 255;
+                 Pixels[X*4+1] = 255;
+                 Pixels[X*4+2] = 255;
+               } else {
+                 Pixels[X*4+0] = 0;
+                 Pixels[X*4+1] = 0;
+                 Pixels[X*4+2] = 0;
+               }
+#endif         
+               X++;
+       }
+}
+
+
+static void OneLine(struct ico_progressive_state *context)
+{
+       context->LineDone = 0;
+       
+       if (context->Lines >= context->Header.height*2) {
+               return;
+       }
+               
+       if (context->Lines <context->Header.height) {           
+
+               if (context->Type == 24)
+                       OneLine24(context);
+               if (context->Type == 8)
+                       OneLine8(context);
+               if (context->Type == 4)
+                       OneLine4(context);
+               if (context->Type == 1)
+                       OneLine1(context);
+       } else
+       {
+               OneLineTransp(context);
+       }
+       
+       context->Lines++;
+       if (context->Lines>=context->Header.height) {
+               context->Type = 1;
+               context->LineWidth = context->Header.width / 8;
+               if ((context->Header.width & 7) != 0)
+                       context->LineWidth++;
+               /* Pad to a 32 bit boundary */
+               if (((context->LineWidth % 4) > 0))
+                       context->LineWidth = (context->LineWidth / 4) * 4 + 4;
+                       
+       }
+         
+
+       if (context->updated_func != NULL) {
+               (*context->updated_func) (context->pixbuf,
+                                         context->user_data,
+                                         0,
+                                         context->Lines,
+                                         context->Header.width,
+                                         context->Header.height);
+
+       }
+}
+
+/*
+ * context - from image_begin_load
+ * buf - new image data
+ * size - length of new image data
+ *
+ * append image data onto inrecrementally built output image
+ */
+gboolean image_load_increment(gpointer data, guchar * buf, guint size)
+{
+       struct ico_progressive_state *context =
+           (struct ico_progressive_state *) data;
+
+       gint BytesToCopy;
+
+       while (size > 0) {
+               printf("Y=%i  C=%i H=%i\n",context->Lines,context->Type,context->Header.height);
+               g_assert(context->LineDone >= 0);
+               if (context->HeaderDone < context->HeaderSize) {        /* We still 
+                                                                          have headerbytes to do */
+                       BytesToCopy =
+                           context->HeaderSize - context->HeaderDone;
+                       if (BytesToCopy > size)
+                               BytesToCopy = size;
+
+                       memcpy(context->HeaderBuf + context->HeaderDone,
+                              buf, BytesToCopy);
+
+                       size -= BytesToCopy;
+                       buf += BytesToCopy;
+                       context->HeaderDone += BytesToCopy;
+
+               }  else
+               {  
+                       BytesToCopy =
+                           context->LineWidth - context->LineDone;
+                       if (BytesToCopy > size)
+                               BytesToCopy = size;
+
+                       if (BytesToCopy > 0) {
+                               memcpy(context->LineBuf +
+                                      context->LineDone, buf,
+                                      BytesToCopy);
+
+                               size -= BytesToCopy;
+                               buf += BytesToCopy;
+                               context->LineDone += BytesToCopy;
+                       }
+                       if ((context->LineDone >= context->LineWidth) &&
+                           (context->LineWidth > 0))
+                               OneLine(context);
+
+
+               }
+
+               if (context->HeaderDone >= 6)
+                       DecodeHeader(context->HeaderBuf,
+                                    context->HeaderDone, context);
+
+
+       }
+
+       return TRUE;
+}